﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Runtime.ConstrainedExecution;
using System.Security;

namespace sy_dll_inject
{
    public class ProcessUtils
    {

        public static class Methods
        {


            [Flags]
            public enum AllocationType
            {
                Commit = 0x1000,
                Reserve = 0x2000,
                Decommit = 0x4000,
                Release = 0x8000,
                Reset = 0x80000,
                Physical = 0x400000,
                TopDown = 0x100000,
                WriteWatch = 0x200000,
                LargePages = 0x20000000
            }

            [Flags]
            public enum MemoryProtection
            {
                Execute = 0x10,
                ExecuteRead = 0x20,
                ExecuteReadWrite = 0x40,
                ExecuteWriteCopy = 0x80,
                NoAccess = 0x01,
                ReadOnly = 0x02,
                ReadWrite = 0x04,
                WriteCopy = 0x08,
                GuardModifierflag = 0x100,
                NoCacheModifierflag = 0x200,
                WriteCombineModifierflag = 0x400
            }
            // 声明我们需要用到的 Windows API 函数
            [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
            public static extern IntPtr VirtualAllocEx(
                IntPtr hProcess, 
                IntPtr lpAddress, 
                uint dwSize, 
                AllocationType flAllocationType,
                MemoryProtection flProtect
            );

            [DllImport("kernel32.dll")]
            public static extern bool WriteProcessMemory(
                 IntPtr hProcess,
                 IntPtr lpBaseAddress,
                 char[] lpBuffer,
                 Int32 nSize,
                 out IntPtr lpNumberOfBytesWritten
            );

            [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
            public static extern IntPtr GetProcAddress(
                IntPtr hModule,
                string procName
            );

            [DllImport("kernel32.dll")]
            public static extern IntPtr CreateRemoteThread(
                IntPtr hProcess,
                IntPtr lpThreadAttributes, 
                uint dwStackSize, 
                IntPtr lpStartAddress,
                IntPtr lpParameter, 
                uint dwCreationFlags, 
                out IntPtr lpThreadId
            );

            [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
            public static extern IntPtr GetModuleHandle(string lpModuleName);

            [DllImport("kernel32.dll", SetLastError = true)]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            [SuppressUnmanagedCodeSecurity]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CloseHandle(IntPtr hObject);
        }


        public static bool DoInjectDllToProcess(Process targetProcess, string dllFile)
        {
            IntPtr allocAddr;
            uint length = (uint)dllFile.Length + 1;
            IntPtr bytesRead = IntPtr.Zero;
            bool writeMemoryRet;
            IntPtr libraryAddr;
            IntPtr hThread;
            // 申请内存空间
            allocAddr = Methods.VirtualAllocEx(
                targetProcess.Handle,
                IntPtr.Zero,
                length,
                Methods.AllocationType.Commit | Methods.AllocationType.Reserve,
                Methods.MemoryProtection.ReadWrite
            );
            if(allocAddr.Equals(0))
            {
                Form1.Log("执行 VirtualAllocEx 时，申请内存空间失败!!!", Form1.log);
                MessageBox.Show("执行 VirtualAllocEx 时，申请内存空间失败!!!");
                return false;
            }

            // 写入内存
            writeMemoryRet = Methods.WriteProcessMemory(targetProcess.Handle, allocAddr, dllFile.ToCharArray(), (int)length,out bytesRead);
            if (!writeMemoryRet || bytesRead.Equals(0))
            {
                Form1.Log("执行 WriteProcessMemory 时，写入内存失败!!!", Form1.log);
                MessageBox.Show("执行 WriteProcessMemory 时，写入内存失败!!!");
                return false;
            }

            // 获取 loadlibrary 在 Kernel32.dll 的地址
            libraryAddr = Methods.GetProcAddress(Methods.GetModuleHandle("Kernel32"), "LoadLibraryA");
            if (libraryAddr.Equals(0))
            {
                Form1.Log("执行 GetProcAddress 时，获取 LoadLibraryA 函数入口地址失败!!!", Form1.log);
                MessageBox.Show("执行 GetProcAddress 时，获取 LoadLibraryA 函数入口地址失败!!!");
                return false;
            }

            // 创建远程线程，注入 dll
            hThread = Methods.CreateRemoteThread(targetProcess.Handle, IntPtr.Zero, 0, libraryAddr, allocAddr, 0, out _);
            if (hThread.Equals(0))
            {
                Form1.Log("执行 CreateRemoteThread 时，创建远程线程失败!!!", Form1.log);
                MessageBox.Show("执行 GetProcAddress 时，创建远程线程失败!!!");
                return false;
            }else
            {
                Methods.CloseHandle(hThread);
            }
            return true;
        }
    }
}
